package hu.bme.mit.inf.seample.gen.util;

import hu.bme.mit.inf.seample.gen.SeamGenerationDescriptor;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import seample.BusinessComponent;
import seample.BusinessService;
import seample.BusinessServiceParameter;
import seample.Component;
import seample.ConversationalMethod;
import seample.DataType;
import seample.EntityType;
import seample.EnumType;
import seample.Method;
import seample.ParameterType;
import seample.PrimitiveType;
import seample.RESTComponent;
import seample.SeamComponent;
import seample.UtilType;
import seample.WSComponent;

public class CodeGeneratorUtil {

	private static SeamGenerationDescriptor selectedDescriptor;
	
	/**
	 * Returns a string containing a return type for a method.
	 * @param method
	 * @return
	 */
	public final static String getReturnType(Method method) {
		if (method == null) {
			throw new IllegalArgumentException("Method is null!");
		}
		String retType = "void";
		if (method.getReturnType() != null) {
			retType = getDataType(method.getReturnType());
		}
		return retType;
	}
	
	public static final String getDataType(ParameterType parameterType) {
		String retType = "";		
		DataType dataType = parameterType.getType();
		if (dataType instanceof PrimitiveType) {
			PrimitiveType type = ((PrimitiveType) dataType);			
			if (parameterType.getMultiplicity() == -1) {
				/**/
				if(type.getType() == null)
					retType = "List<" + type.getName() + ">";
				/**/
				else
					retType = "List<" + type.getType().getName() + ">";
			} else {
				/**/
				if(type.getType() == null)
					retType = ((PrimitiveType) dataType).getName();
				/**/
				else
					retType = ((PrimitiveType) dataType).getType().getName();
			}
		}
		if (dataType instanceof EntityType) {
			EntityType type = ((EntityType) dataType);
			if (parameterType.getMultiplicity() == -1) {
				retType = "List<" + type.getType().getName() + ">";
			} else {
				retType = type.getType().getName();
			}
		}
		if(dataType instanceof UtilType) {
			UtilType type = ((UtilType) dataType);
			if (parameterType.getMultiplicity() == -1) {
				/**/
				if(type.getType() == null)
					retType = "List<" + getShortName(type) + ">";
				/**/
				else
					retType = "List<" + type.getType().getName() + ">";
			} else {
				/**/
				if(type.getType() == null)
					retType = getShortName(type);
				/**/
				else
					retType = ((UtilType) dataType).getType().getName();
			}
		}
		return retType;
	}

	/**
	 * Returns the input parameters for a method. 
	 * @param method
	 * @return
	 */
	public static final String getParameters(Method method) {
		String parameters = "";
		if (method instanceof BusinessService) {
			for (Iterator<BusinessServiceParameter> iter = ((BusinessService) method).getParameters().iterator(); iter.hasNext();) {
				BusinessServiceParameter parameter = iter.next();
				parameters += getDataType(parameter);
				parameters += " ";
				parameters += parameter.getName();
				if (iter.hasNext()) {
					parameters += ", ";
				}
			}
		}
		return parameters;
	}
	
	public static final String getShortName(UtilType ut)
	{
		String result = null;
		
		if(ut.getName().contains("."))
		{
			String convertedname = ut.getName().replace(".", ":");
			String[] splittedname = convertedname.split(":");
			result = splittedname[splittedname.length-1];
		}
		else
		{
			result = ut.getName();
		}		
		return result;
	}
	
	public static final String getShortName(SeamComponent sc)
	{
		String result = null;
		
		if(sc.getSeamName().contains("."))
		{
			String convertedname = sc.getSeamName().replace(".", ":");
			String[] splittedname = convertedname.split(":");
			result = splittedname[splittedname.length-1];
		}
		else
		{
			result = sc.getSeamName();
		}		
		return result;
	}
	
	public static final String getName(Component sc)
	{
		String result = null;
		result = sc.getClassName();
		return result;
	}
	
	
	/**
	 * A Set of packages to be imported.
	 */
	static Set<String> importMap = new HashSet<String>();
	
	/**
	 * 
	 * @param sc
	 * @return
	 */
	public static final String makeImportEntry(UtilType ut)
	{		
		String result = null;
		
		if(!importMap.contains(ut.getName()))
		{
			importMap.add(ut.getName());
		}		
		
		return result;
	}
	
	public static final String makeImportEntry(EnumType et)
	{		
		String result = null;
		
		if(!importMap.contains(getPackageFor(et)+"."+et.getName()))
		{
			importMap.add(getPackageFor(et)+"."+et.getName());
		}		
		
		return result;
	}
	
	public static final String makeImportEntry(EntityType et)
	{		
		String result = null;
		
		if(!importMap.contains(getPackageFor(et)+"."+et.getName()))
		{
			importMap.add(getPackageFor(et)+"."+et.getName());
		}		
		
		return result;
	}
	
	public static final String makeImportEntry(ConversationalMethod cm)
	{		
		String result = null;
		
		if(cm.isConvBegin())
		{
			if(!importMap.contains("org.jboss.seam.annotations.Begin"))
				importMap.add("org.jboss.seam.annotations.Begin");
		}
		if(cm.isConvEnd())
		{
			if(!importMap.contains("org.jboss.seam.annotations.End"))
				importMap.add("org.jboss.seam.annotations.End");
		}
		
		return result;
	}
	
	public static final String getImportEntries()
	{
		String importLines = "";
		
		for(String line : importMap)
		{
			importLines += "import " + line + ";\n";
		}
		
		return importLines;
	}
	
	public static final String deleteImportEntries()
	{
		importMap.clear();
		return "";
	}
	
	/**
	 * Returns the package name for the given component.
	 * @param component
	 * @return
	 */
	public static final String getPackageFor(Object component) {
		String pName = "";
		SeamGenerationDescriptor descriptor = getSelectedDescriptor();
		if (component instanceof BusinessComponent) {
			pName = descriptor.getSessionPackage();
		}
		if (component instanceof RESTComponent) {
			pName = descriptor.getRestPackage();
		}
		if (component instanceof WSComponent) {
			pName = descriptor.getWsPackage();
		}
		if (component instanceof EntityType || component instanceof EnumType) {
			pName = descriptor.getEntityPackge();
		}
		return pName;
	}

	public static void setSelectedDescriptor(SeamGenerationDescriptor selectedDescriptor) {
		CodeGeneratorUtil.selectedDescriptor = selectedDescriptor;
	}

	public static SeamGenerationDescriptor getSelectedDescriptor() {
		return selectedDescriptor;
	}
	
}
